home *** CD-ROM | disk | FTP | other *** search
- Subject: v25i010: trn 2.0 - threaded newsreader based on rn 4.4, Part07/13
- Newsgroups: comp.sources.unix
- Approved: vixie@pa.dec.com
-
- Submitted-by: davison@borland.com (Wayne Davison)
- Posting-number: Volume 25, Issue 10
- Archive-name: trn/part07
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 7 (of 13)."
- # Contents: bits.c respond.c rt-rn.c rt-select.c
- # Wrapped by vixie@cognition.pa.dec.com on Tue Dec 3 16:34:54 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'bits.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'bits.c'\"
- else
- echo shar: Extracting \"'bits.c'\" \(18289 characters\)
- sed "s/^X//" >'bits.c' <<'END_OF_FILE'
- X/* $Id: bits.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
- X *
- X * $Log: bits.c,v $
- X * Revision 4.4 1991/09/09 20:18:23 sob
- X * release 4.4
- X *
- X *
- X *
- X */
- X/* This software is Copyright 1991 by Stan Barber.
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction of this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "rcstuff.h"
- X#include "head.h"
- X#include "util.h"
- X#include "final.h"
- X#include "rn.h"
- X#include "cheat.h"
- X#include "ng.h"
- X#include "artio.h"
- X#include "intrp.h"
- X#include "ngdata.h"
- X#include "rcln.h"
- X#include "kfile.h"
- X#ifdef USETHREADS
- X#include "threads.h"
- X#include "rthreads.h"
- X#endif
- X#include "INTERN.h"
- X#include "bits.h"
- X
- X#ifdef DBM
- X# ifdef NULL
- X# undef NULL
- X# endif
- X# include <dbm.h>
- X#endif
- MEM_SIZE ctlsize; /* size of bitmap in bytes */
- X
- void
- bits_init()
- X{
- X#ifdef DELAYMARK
- X dmname = savestr(filexp(RNDELNAME));
- X#else
- X ;
- X#endif
- X}
- X
- X/* checkpoint the .newsrc */
- X
- void
- checkpoint_rc()
- X{
- X#ifdef DEBUGGING
- X if (debug & DEB_CHECKPOINTING) {
- X fputs("(ckpt)",stdout);
- X fflush(stdout);
- X }
- X#endif
- X if (doing_ng)
- X restore_ng(); /* do not restore M articles */
- X if (rc_changed)
- X write_rc();
- X#ifdef DEBUGGING
- X if (debug & DEB_CHECKPOINTING) {
- X fputs("(done)",stdout);
- X fflush(stdout);
- X }
- X#endif
- X}
- X
- X/* reconstruct the .newsrc line in a human readable form */
- X
- void
- restore_ng()
- X{
- X register char *s, *mybuf = buf;
- X register ART_NUM i;
- X ART_NUM count=0;
- X int safelen = LBUFLEN - 16;
- X
- X strcpy(buf,rcline[ng]); /* start with the newsgroup name */
- X s = buf + rcnums[ng] - 1; /* use s for buffer pointer */
- X#ifdef USETHREADS
- X *s++ = RCCHAR(rcchar[ng]); /* put the requisite : or !*/
- X#else
- X *s++ = rcchar[ng]; /* put the requisite : or !*/
- X#endif
- X *s++ = ' '; /* put the not-so-requisite space */
- X for (i=1; i<=lastart; i++) { /* for each article in newsgroup */
- X if (s-mybuf > safelen) { /* running out of room? */
- X safelen *= 2;
- X if (mybuf == buf) { /* currently static? */
- X *s = '\0';
- X mybuf = safemalloc((MEM_SIZE)safelen + 16);
- X strcpy(mybuf,buf); /* so we must copy it */
- X s = mybuf + (s-buf);
- X /* fix the pointer, too */
- X }
- X else { /* just grow in place, if possible */
- X char *newbuf;
- X
- X newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
- X s = newbuf + (s-mybuf);
- X mybuf = newbuf;
- X }
- X }
- X if (!was_read(i)) /* still unread? */
- X count++; /* then count it */
- X else { /* article was read */
- X ART_NUM oldi;
- X
- X sprintf(s,"%ld",(long)i); /* put out the min of the range */
- X s += strlen(s); /* keeping house */
- X oldi = i; /* remember this spot */
- X do i++; while (i <= lastart && was_read(i));
- X /* find 1st unread article or end */
- X i--; /* backup to last read article */
- X if (i > oldi) { /* range of more than 1? */
- X sprintf(s,"-%ld,",(long)i);
- X /* then it out as a range */
- X s += strlen(s); /* and housekeep */
- X }
- X else
- X *s++ = ','; /* otherwise, just a comma will do */
- X }
- X }
- X if (*(s-1) == ',') /* is there a final ','? */
- X s--; /* take it back */
- X *s++ = '\0'; /* and terminate string */
- X#ifdef DEBUGGING
- X if (debug & DEB_NEWSRC_LINE && !panic) {
- X printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
- X printf("%s\n",mybuf) FLUSH;
- X }
- X#endif
- X free(rcline[ng]); /* return old rc line */
- X if (mybuf == buf) {
- X rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
- X /* grab a new rc line */
- X strcpy(rcline[ng], buf); /* and load it */
- X }
- X else {
- X mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
- X /* be nice to the heap */
- X rcline[ng] = mybuf;
- X }
- X *(rcline[ng] + rcnums[ng] - 1) = '\0';
- X if (rcchar[ng] == NEGCHAR) { /* did they unsubscribe? */
- X printf(unsubto,ngname) FLUSH;
- X toread[ng] = TR_UNSUB; /* make line invisible */
- X }
- X else
- X /*NOSTRICT*/
- X toread[ng] = (ART_UNREAD)count; /* remember how many unread there are */
- X}
- X
- X/* mark an article unread, keeping track of toread[] */
- X
- void
- onemore(artnum)
- ART_NUM artnum;
- X{
- X#ifdef DEBUGGING
- X if (debug && artnum < firstbit) {
- X printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
- X return;
- X }
- X#endif
- X if (ctl_read(artnum)) {
- X ctl_clear(artnum);
- X ++toread[ng];
- X }
- X}
- X
- X/* mark an article read, keeping track of toread[] */
- X
- void
- oneless(artnum)
- ART_NUM artnum;
- X{
- X#ifdef DEBUGGING
- X if (debug && artnum < firstbit) {
- X printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
- X return;
- X }
- X#endif
- X if (!ctl_read(artnum)) {
- X ctl_set(artnum);
- X if (toread[ng] > TR_NONE)
- X --toread[ng];
- X }
- X}
- X
- X/* mark an article as unread, making sure that firstbit is properly handled */
- X/* cross-references are left as read in the other newsgroups */
- X
- void
- unmark_as_read()
- X{
- X check_first(art);
- X#ifdef USETHREADS
- X find_article(art);
- X /* Keep selected_count accurate */
- X if (ctl_read(art)) {
- X if (p_art) {
- X if (selected_roots[p_art->root]) {
- X selected_count++;
- X }
- X root_article_cnts[p_art->root] = 1;
- X } else
- X unthreaded++;
- X }
- X scan_all_roots = FALSE;
- X#endif
- X onemore(art);
- X#ifdef MCHASE
- X# ifdef USETHREADS
- X if ((olden_days > 1 || !p_art || (p_art->flags & HAS_XREFS))
- X && !parse_maybe(art))
- X# else
- X if (!parse_maybe(art))
- X# endif
- X chase_xrefs(art,FALSE);
- X#endif
- X}
- X
- X#ifdef USETHREADS
- X/* mark an article as read in this newsgroup and possibly chase xrefs.
- X** p_art must be set to the current article's data.
- X*/
- X
- void
- set_read(artnum,selected,chase_xrefs_flag)
- ART_NUM artnum;
- int selected;
- bool_int chase_xrefs_flag;
- X{
- X if (!ctl_read(artnum)) {
- X oneless(artnum);
- X if (p_art->subject != -1)
- X selected_count -= selected;
- X }
- X if (chase_xrefs_flag && (p_art->flags & HAS_XREFS)) {
- X if (output_chase_phrase) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\nChasing xrefs", stdout);
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nXrefs", stdout);
- X#endif
- X output_chase_phrase = 0;
- X }
- X putchar('.'), fflush(stdout);
- X chase_xrefs(artnum, TRUE);
- X }
- X}
- X
- X/* mark an article as unread in this newsgroup only.
- X** p_art must be set to the current article's data.
- X*/
- X
- void
- set_unread(artnum,selected)
- ART_NUM artnum;
- int selected;
- X{
- X if (artnum >= absfirst) {
- X check_first(artnum);
- X if (ctl_read(artnum)) {
- X onemore(artnum);
- X selected_count += selected;
- X root_article_cnts[p_art->root] = 1;
- X scan_all_roots = FALSE;
- X }
- X }
- X}
- X#endif
- X
- X#ifdef DELAYMARK
- X/* temporarily mark article as read. When newsgroup is exited, articles */
- X/* will be marked as unread. Called via M command */
- X
- void
- delay_unmark(artnum)
- ART_NUM artnum;
- X{
- X if (dmfp == Nullfp) {
- X dmfp = fopen(dmname,"w+");
- X if (dmfp == Nullfp) {
- X printf(cantcreate,dmname) FLUSH;
- X sig_catcher(0);
- X }
- X }
- X#ifdef USETHREADS
- X /* Keep selected_count accurate */
- X if (!ctl_read(artnum)) {
- X find_article(artnum);
- X if (p_art) {
- X if (selected_roots[p_art->root])
- X selected_count--;
- X } else
- X unthreaded--;
- X }
- X#endif
- X oneless(artnum); /* set the correct bit */
- X dmcount++;
- X fprintf(dmfp,"%ld\n",(long)artnum);
- X}
- X#endif
- X
- X/* mark article as read. If article is cross referenced to other */
- X/* newsgroups, mark them read there also. */
- X
- void
- mark_as_read()
- X{
- X#ifdef USETHREADS
- X find_article(art);
- X /* Keep selected_count accurate */
- X if (!ctl_read(art)) {
- X if (p_art) {
- X if (selected_roots[p_art->root])
- X selected_count--;
- X } else
- X unthreaded--;
- X }
- X#endif
- X oneless(art); /* set the correct bit */
- X checkcount++; /* get more worried about crashes */
- X#ifdef USETHREADS
- X if (olden_days > 1 || !p_art || (p_art->flags & HAS_XREFS))
- X#endif
- X chase_xrefs(art,TRUE);
- X}
- X
- X/* make sure we have bits set correctly down to firstbit */
- X
- void
- check_first(min)
- ART_NUM min;
- X{
- X register ART_NUM i = firstbit;
- X
- X if (min < absfirst)
- X min = absfirst;
- X if (min < i) {
- X for (i--; i>=min; i--)
- X ctl_set(i); /* mark as read */
- X firstart = firstbit = min;
- X }
- X}
- X
- X/* bring back articles marked with M */
- X
- X#ifdef DELAYMARK
- void
- yankback()
- X{
- X if (dmfp) { /* delayed unmarks pending? */
- X#ifdef VERBOSE
- X printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
- X dmcount == 1 ? nullstr : "s") FLUSH;
- X#endif
- X rewind(dmfp);
- X while (fgets(buf,sizeof buf,dmfp) != Nullch) {
- X art = (ART_NUM)atol(buf);
- X unmark_as_read();
- X }
- X fclose(dmfp);
- X dmfp = Nullfp;
- X UNLINK(dmname); /* and be tidy */
- X }
- X dmcount = 0;
- X}
- X#endif
- X
- X/* run down xref list and mark as read or unread */
- X
- int
- chase_xrefs(artnum,markread)
- ART_NUM artnum;
- int markread;
- X{
- X#ifdef ASYNC_PARSE
- X if (parse_maybe(artnum)) /* make sure we have right header */
- X return -1;
- X#endif
- X#ifdef DBM
- X {
- X datum lhs, rhs;
- X datum fetch();
- X register char *idp;
- X char *ident_buf;
- X static FILE * hist_file = Nullfp;
- X#else
- X if (
- X#ifdef DEBUGGING
- X debug & DEB_FEED_XREF ||
- X#endif
- X htype[XREF_LINE].ht_minpos >= 0) {
- X /* are there article# xrefs? */
- X#endif /* DBM */
- X char *xref_buf, *curxref;
- X register char *xartnum;
- X char *rver_buf = Nullch;
- X static char *inews_site = Nullch;
- X register ART_NUM x;
- X char tmpbuf[128];
- X#ifdef DBM
- X long pos;
- X rver_buf = fetchlines(artnum,NGS_LINE);
- X /* get Newsgroups */
- X#ifdef XREF_WITH_COMMAS
- X if (!index(rver_buf,',')) /* if no comma, no Xref! */
- X return 0;
- X#endif
- X if (hist_file == Nullfp) { /* Init. file accesses */
- X#ifdef DEBUGGING
- X if (debug)
- X printf ("chase_xref: opening files\n");
- X#endif
- X dbminit(filexp(ARTFILE));
- X if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
- X return 0;
- X }
- X xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
- X ident_buf = fetchlines(artnum,MESSID_LINE);
- X /* get Message-ID */
- X#ifdef DEBUGGING
- X if (debug)
- X printf ("chase_xref: Message-ID: %s\n", ident_buf);
- X#endif
- X idp = ident_buf;
- X while (*++idp) /* make message-id case insensitive */
- X if (isupper(*idp))
- X *idp = tolower (*idp);
- X lhs.dptr = ident_buf; /* look up article by id */
- X lhs.dsize = strlen(lhs.dptr) + 1;
- X rhs = fetch(lhs); /* fetch the record */
- X if (rhs.dptr == NULL) /* if null, nothing there */
- X goto wild_goose;
- X bcopy((void *)rhs.dptr,(void *)&pos, 4);
- X fseek (hist_file, pos, 0);
- X /* datum returned is position in hist file */
- X fgets (xref_buf, BUFSIZ, hist_file);
- X#ifdef DEBUGGING
- X if (debug)
- X printf ("Xref from history: %s\n", xref_buf);
- X#endif
- X curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
- X curxref = cpytill(tmpbuf, curxref, '\t') + 1;
- X#ifdef DEBUGGING
- X if (debug)
- X printf ("chase_xref: curxref: %s\n", curxref);
- X#endif
- X#else /* !DBM */
- X#ifdef DEBUGGING
- X if (htype[XREF_LINE].ht_minpos >= 0)
- X#endif
- X xref_buf = fetchlines(artnum,XREF_LINE);
- X /* get xrefs list */
- X#ifdef DEBUGGING
- X else {
- X xref_buf = safemalloc((MEM_SIZE)100);
- X printf("Give Xref: ") FLUSH;
- X gets(xref_buf);
- X }
- X#endif
- X#ifdef DEBUGGING
- X if (debug & DEB_XREF_MARKER)
- X printf("Xref: %s\n",xref_buf) FLUSH;
- X#endif
- X curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
- X
- X /* Make sure site name on Xref matches what inews thinks site is.
- X * Check first against last inews_site. If it matches, fine.
- X * If not, fetch inews_site from current Relay-Version line and
- X * check again. This is so that if the new administrator decides
- X * to change the system name as known to inews, rn will still do
- X * Xrefs correctly--each article need only match itself to be valid.
- X */
- X if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
- X#ifndef NORELAY
- X char *t;
- X#endif
- X if (inews_site != Nullch)
- X free(inews_site);
- X#ifndef NORELAY
- X rver_buf = fetchlines(artnum,RVER_LINE);
- X if ((t = instr(rver_buf,"; site "), TRUE) == Nullch)
- X#else /* NORELAY */
- X /* In version 2.10.3 of news or afterwards, the Relay-Version
- X * and Posting-Version header lines have been removed. For
- X * the code below to work as intended, I have modified it to
- X * extract the first component of the Path header line. This
- X * should give the same effect as did the old code with respect
- X * to the use of the Relay-Version site name.
- X */
- X rver_buf = fetchlines(artnum,PATH_LINE);
- X if (instr(rver_buf,"!", TRUE) == Nullch)
- X#endif /* NORELAY */
- X inews_site = savestr(nullstr);
- X else {
- X char new_site[128];
- X
- X#ifndef NORELAY
- X cpytill(new_site,t + 7,'.');
- X#else /* NORELAY */
- X cpytill(new_site,rver_buf,'!');
- X#endif /* NORELAY */
- X inews_site = savestr(new_site);
- X }
- X if (strNE(tmpbuf,inews_site)) {
- X#ifdef DEBUGGING
- X if (debug)
- X printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
- X#endif
- X goto wild_goose;
- X }
- X }
- X#endif /* DBM */
- X while (*curxref) {
- X /* for each newsgroup */
- X curxref = cpytill(tmpbuf,curxref,' ');
- X#ifdef DBM
- X xartnum = index(tmpbuf,'/');
- X#else
- X xartnum = index(tmpbuf,':');
- X#endif /* DBM */
- X if (!xartnum) /* probably an old-style Xref */
- X break;
- X *xartnum++ = '\0';
- X if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
- X x = atol(xartnum);
- X if (x)
- X if (markread) {
- X if (addartnum(x,tmpbuf))
- X goto wild_goose;
- X }
- X#ifdef MCHASE
- X else
- X subartnum(x,tmpbuf);
- X#endif
- X }
- X while (*curxref && isspace(*curxref))
- X curxref++;
- X }
- X wild_goose:
- X free(xref_buf);
- X#ifdef DBM
- X free(ident_buf);
- X#endif /* DBM */
- X if (rver_buf != Nullch)
- X free(rver_buf);
- X }
- X return 0;
- X}
- X
- int
- initctl()
- X{
- X char *mybuf = buf; /* place to decode rc line */
- X register char *s, *c, *h;
- X register long i;
- X register ART_NUM unread;
- X
- X#ifdef DELAYMARK
- X dmcount = 0;
- X#endif
- X if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */
- X return -1;
- X
- X absfirst = getabsfirst(ng,lastart); /* remember first existing article */
- X if (!absfirst) /* no articles at all? */
- X absfirst = 1; /* pretend there is one */
- X#ifndef lint
- X ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
- X#endif /* lint */
- X ctlarea = safemalloc(ctlsize); /* allocate control area */
- X
- X /* now modify ctlarea to reflect what has already been read */
- X
- X for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
- X /* find numbers in rc line */
- X i = strlen(s);
- X#ifndef lint
- X if (i >= LBUFLEN-2) /* bigger than buf? */
- X mybuf = safemalloc((MEM_SIZE)(i+2));
- X#endif /* lint */
- X strcpy(mybuf,s); /* make scratch copy of line */
- X mybuf[i++] = ','; /* put extra comma on the end */
- X mybuf[i] = '\0';
- X s = mybuf; /* initialize the for loop below */
- X#ifdef USETHREADS
- X if (strnEQ(s,"1-",2)
- X || strnEQ(s,"0-",2)) { /* can we save some time here? */
- X#else
- X if (strnEQ(s,"1-",2)) { /* can we save some time here? */
- X#endif
- X firstbit = atol(s+2)+1; /* ignore first range thusly */
- X s=index(s,',') + 1;
- X }
- X else
- X firstbit = 1; /* all the bits are valid for now */
- X if (absfirst > firstbit) { /* do we know already? */
- X firstbit = absfirst; /* no point calling getngmin again */
- X }
- X else if (artopen(firstbit) == Nullfp) {
- X /* first unread article missing? */
- X i = getngmin(".",firstbit); /* see if expire has been busy */
- X if (i) { /* avoid a bunch of extra opens */
- X firstbit = i;
- X }
- X }
- X firstart = firstbit; /* firstart > firstbit in KILL */
- X#ifdef PENDING
- X# ifdef CACHESUBJ
- X subj_to_get = firstbit;
- X# endif
- X#endif
- X unread = lastart - firstbit + 1; /* assume this range unread */
- X for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
- X ctlarea[i] = 0; /* assume unread */
- X#ifdef DEBUGGING
- X if (debug & DEB_CTLAREA_BITMAP) {
- X printf("\n%s\n",mybuf) FLUSH;
- X for (i=1; i <= lastart; i++)
- X if (! was_read(i))
- X printf("%ld ",(long)i) FLUSH;
- X }
- X#endif
- X for ( ; (c = index(s,',')) != Nullch; s = ++c) {
- X /* for each range */
- X ART_NUM min, max;
- X
- X *c = '\0'; /* do not let index see past comma */
- X if ((h = index(s,'-')) != Nullch) { /* is there a -? */
- X min = atol(s);
- X max = atol(h+1);
- X if (min < firstbit) /* make sure range is in range */
- X min = firstbit;
- X if (max > lastart)
- X max = lastart;
- X if (min <= max) /* non-null range? */
- X unread -= max - min + 1;/* adjust unread count */
- X for (i=min; i<=max; i++) /* for all articles in range */
- X ctl_set(i); /* mark them read */
- X }
- X else if ((i = atol(s)) >= firstbit && i <= lastart) {
- X /* is single number reasonable? */
- X ctl_set(i); /* mark it read */
- X unread--; /* decrement articles to read */
- X }
- X#ifdef DEBUGGING
- X if (debug & DEB_CTLAREA_BITMAP) {
- X printf("\n%s\n",s) FLUSH;
- X for (i=1; i <= lastart; i++)
- X if (! was_read(i))
- X printf("%ld ",(long)i) FLUSH;
- X }
- X#endif
- X }
- X#ifdef DEBUGGING
- X if (debug & DEB_CTLAREA_BITMAP) {
- X fputs("\n(hit CR)",stdout) FLUSH;
- X gets(cmd_buf);
- X }
- X#endif
- X if (mybuf != buf)
- X free(mybuf);
- X toread[ng] = unread;
- X return 0;
- X}
- X
- void
- grow_ctl(newlast)
- ART_NUM newlast;
- X{
- X ART_NUM tmpfirst;
- X MEM_SIZE newsize;
- X register ART_NUM i;
- X
- X forcegrow = FALSE;
- X if (newlast > lastart) {
- X ART_NUM tmpart = art;
- X#ifndef lint
- X newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
- X#else
- X newsize = Null(MEM_SIZE);
- X#endif /* lint */
- X if (newsize > ctlsize) {
- X newsize += 20;
- X ctlarea = saferealloc(ctlarea,newsize);
- X ctlsize = newsize;
- X }
- X toread[ng] += (ART_UNREAD)(newlast-lastart);
- X for (i=lastart+1; i<=newlast; i++)
- X ctl_clear(i); /* these articles are unread */
- X#ifdef CACHESUBJ
- X if (subj_list != Null(char**)) {
- X#ifndef lint
- X subj_list = (char**)saferealloc((char*)subj_list,
- X (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
- X#endif /* lint */
- X for (i=lastart+1; i<=newlast; i++)
- X subj_list[OFFSET(i)] = Nullch;
- X }
- X#endif
- X tmpfirst = lastart+1;
- X lastart = newlast;
- X#ifdef KILLFILES
- X#ifdef VERBOSE
- X IF(verbose)
- X sprintf(buf,
- X "%ld more article%s arrived--looking for more to kill...\n\n",
- X (long)(lastart - tmpfirst + 1),
- X (lastart > tmpfirst ? "s have" : " has" ) );
- X ELSE /* my, my, how clever we are */
- X#endif
- X#ifdef TERSE
- X strcpy(buf, "More news--killing...\n\n");
- X#endif
- X kill_unwanted(tmpfirst,buf,TRUE);
- X#endif
- X art = tmpart;
- X }
- X}
- X
- END_OF_FILE
- if test 18289 -ne `wc -c <'bits.c'`; then
- echo shar: \"'bits.c'\" unpacked with wrong size!
- fi
- # end of 'bits.c'
- fi
- if test -f 'respond.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'respond.c'\"
- else
- echo shar: Extracting \"'respond.c'\" \(19717 characters\)
- sed "s/^X//" >'respond.c' <<'END_OF_FILE'
- X/* $Id: respond.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
- X *
- X * $Log: respond.c,v $
- X * Revision 4.4.2.1 1991/12/01 18:05:42 sob
- X * Patchlevel 2 changes
- X *
- X * Revision 4.4.1.1 1991/09/25 19:38:08 sob
- X * Some adaptions for CNEWS
- X *
- X * Revision 4.4 1991/09/09 20:27:37 sob
- X * release 4.4
- X *
- X *
- X *
- X */
- X/* This software is Copyright 1991 by Stan Barber.
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction or this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "intrp.h"
- X#include "head.h"
- X#include "term.h"
- X#include "ng.h"
- X#include "util.h"
- X#include "rn.h"
- X#include "artio.h"
- X#include "final.h"
- X#include "bits.h"
- X#include "decode.h"
- X#include "INTERN.h"
- X#include "respond.h"
- X
- static char nullart[] = "\nNull article\n";
- X
- void
- respond_init()
- X{
- X ;
- X}
- X
- int
- save_article()
- X{
- X bool use_pref, cut_line();
- X register char *s, *c;
- X char altbuf[CBUFLEN];
- X int iter;
- X bool interactive = (buf[1] == FINISHCMD);
- X char cmd = *buf;
- X
- X if (!finish_command(interactive)) /* get rest of command */
- X return SAVE_ABORT;
- X if ((use_pref = isupper(cmd)) != 0)
- X cmd = tolower(cmd);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X savefrom = (cmd == 'w' || cmd == 'e' ? htype[PAST_HEADER].ht_minpos : 0);
- X if (artopen(art) == Nullfp) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\
- Saving null articles is not very productive! :-)\n\
- X",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs(nullart,stdout) FLUSH;
- X#endif
- X return SAVE_DONE;
- X }
- X if (chdir(cwd)) {
- X printf(nocd,cwd) FLUSH;
- X sig_catcher(0);
- X }
- X if (cmd == 'e') { /* is this an extract command? */
- X static bool custom_extract = FALSE;
- X int cnt = 0;
- X bool found_cut = FALSE;
- X char art_buf[LBUFLEN], *cmdstr;
- X
- X s = buf+1; /* skip e */
- X while (*s == ' ') s++; /* skip leading spaces */
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X s = altbuf;
- X if (*s) {
- X cmdstr = cpytill(buf,s,'|'); /* check for | */
- X s = buf + strlen(buf)-1;
- X while (*s == ' ') s--; /* trim trailing spaces */
- X *++s = '\0';
- X if (*cmdstr) {
- X s = cmdstr+1; /* skip | */
- X while (*s == ' ') s++;
- X if (*s) { /* if new command, use it */
- X if (extractprog)
- X free(extractprog);
- X extractprog = savestr(s); /* put extracter in %e */
- X }
- X else
- X cmdstr = extractprog;
- X }
- X else
- X cmdstr = Nullch;
- X s = buf;
- X }
- X else {
- X if (extractdest)
- X strcpy(s, extractdest);
- X if (custom_extract)
- X cmdstr = extractprog;
- X else
- X cmdstr = Nullch;
- X }
- X if (cmdstr) {
- X if (strEQ(extractprog,"-"))
- X cmdstr = Nullch;
- X else if (decode_fp != Nullfp)
- X decode_end();
- X }
- X custom_extract = (cmdstr != 0);
- X
- X fseek(artfp,savefrom,0);
- X if (*s != '/') { /* relative path? */
- X c = (s==buf ? altbuf : buf);
- X interp(c, (sizeof buf), getval("SAVEDIR",SAVEDIR));
- X if (makedir(c,MD_DIR)) /* ensure directory exists */
- X strcpy(c,cwd);
- X if (*s) {
- X while (*c) c++;
- X *c++ = '/';
- X strcpy(c,s); /* add filename */
- X }
- X s = (s==buf ? altbuf : buf);
- X }
- X if (*s != '/') { /* path still relative? */
- X c = (s==buf ? altbuf : buf);
- X sprintf(c, "%s/%s", cwd, s);
- X s = c; /* absolutize it */
- X }
- X if (decode_fp != Nullfp) {
- X printf("Continuing %s:%s\n", decode_fname,
- X cmd != '\0' && strNE(extractdest,s) ?
- X " (Ignoring conflicting directory)" : nullstr ) FLUSH;
- X if (decode_type == UUDECODE)
- X uudecode(artfp);
- X else
- X unship(artfp);
- X }
- X else {
- X if (extractdest)
- X free(extractdest);
- X s = extractdest = savestr(s); /* make it handy for %E */
- X if (makedir(s, MD_DIR)) { /* ensure directory exists */
- X int_count++;
- X return SAVE_DONE;
- X }
- X if (chdir(s)) {
- X printf(nocd,s) FLUSH;
- X sig_catcher(0);
- X }
- X s = getwd(buf); /* simplify path for output */
- X while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- X if (*art_buf <= ' ')
- X continue; /* Ignore empty or initially-whitespace lines */
- X if (found_cut && custom_extract) {
- X printf("Extracting data into %s using %s:\n",
- X s, extractprog) FLUSH;
- X goto extract_it;
- X }
- X if (((*art_buf == '#' || *art_buf == ':')
- X && (strnEQ(art_buf+1, "! /bin/sh", 9)
- X || strnEQ(art_buf+1, "!/bin/sh", 8)
- X || strnEQ(art_buf+2, "This is ", 8)))
- X || strnEQ(art_buf, "sed ", 4)
- X || strnEQ(art_buf, "cat ", 4)
- X || strnEQ(art_buf, "echo ", 5)) {
- X fseek(artfp,-(long)strlen(art_buf)-NL_SIZE+1,1);
- X savefrom = ftell(artfp);
- X if (custom_extract) {
- X printf("Extracting shar into %s using %s:\n",
- X s, extractprog) FLUSH;
- X goto extract_it;
- X }
- X /* Check for special-case of shar'ed-uuencoded file */
- X while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- X if (*art_buf == '#' || *art_buf == ':'
- X || strnEQ(art_buf, "echo ", 5)
- X || strnEQ(art_buf, "sed ", 4))
- X continue;
- X if (strnEQ(art_buf, "Xbegin ", 7)) {
- X decode_type = UUDECODE;
- X goto decode_it;
- X }
- X break;
- X }
- X printf("Extracting shar into %s:\n", s) FLUSH;
- X if (extractprog)
- X free(extractprog);
- X extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
- X extract_it:
- X cnt = 0;
- X interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
- X termlib_reset();
- X resetty(); /* restore tty state */
- X doshell(SH,cmd_buf);
- X noecho(); /* revert to cbreaking */
- X crmode();
- X termlib_init();
- X break;
- X }
- X else
- X if (!custom_extract
- X && (strEQ(art_buf,"$\n")
- X || strEQ(art_buf,"$ f\n"))) {
- X savefrom = ftell(artfp)-strlen(art_buf)-NL_SIZE+1;
- X if (found_cut
- X || (fgets(art_buf,LBUFLEN,artfp) != Nullch
- X && (strnEQ(art_buf, "ship ", 5)
- X || strnEQ(art_buf, "cont ", 5)))) {
- X decode_type = UNSHIP;
- X goto decode_it;
- X }
- X }
- X else
- X if (!custom_extract
- X && (strEQ(art_buf,"table\n")
- X || strnEQ(art_buf,"begin ", 6))) {
- X decode_type = UUDECODE;
- X savefrom = ftell(artfp)-strlen(art_buf)-NL_SIZE+1;
- X decode_it:
- X printf("Extracting %s file into %s:\n",
- X decode_type == UNSHIP? "shipped":"uuencoded", s) FLUSH;
- X if (extractprog)
- X free(extractprog);
- X extractprog = savestr("-");
- X fseek(artfp, savefrom, 0);
- X cnt = 0;
- X if (decode_type == UUDECODE) {
- X uud_start();
- X uudecode(artfp);
- X } else
- X unship(artfp);
- X break;
- X }
- X else {
- X if (cut_line(art_buf)) {
- X savefrom = ftell(artfp);
- X found_cut = TRUE;
- X }
- X else if (found_cut || ++cnt == 300) {
- X break;
- X }
- X }
- X }/* while */
- X if (cnt) {
- X if (custom_extract)
- X printf("Didn't find cut line for extraction to '%s'.\n",
- X extractprog) FLUSH;
- X else
- X printf("Unable to determine type of file.\n") FLUSH;
- X }
- X }/* if */
- X }
- X else if ((s = index(buf,'|')) != Nullch) {
- X /* is it a pipe command? */
- X s++; /* skip the | */
- X while (*s == ' ') s++;
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X if (savedest)
- X free(savedest);
- X savedest = savestr(altbuf);
- X interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
- X /* then set up for command */
- X termlib_reset();
- X resetty(); /* restore tty state */
- X if (use_pref) /* use preferred shell? */
- X doshell(Nullch,cmd_buf);
- X /* do command with it */
- X else
- X doshell(sh,cmd_buf); /* do command with sh */
- X noecho(); /* and stop echoing */
- X crmode(); /* and start cbreaking */
- X termlib_init();
- X }
- X else { /* normal save */
- X bool there, mailbox;
- X char *savename = getval("SAVENAME",SAVENAME);
- X
- X s = buf+1; /* skip s or S */
- X if (*s == '-') { /* if they are confused, skip - also */
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("Warning: '-' ignored. This isn't readnews.\n",stdout)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("'-' ignored.\n",stdout) FLUSH;
- X#endif
- X s++;
- X }
- X for (; *s == ' '; s++); /* skip spaces */
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X s = altbuf;
- X if (! index(s,'/')) {
- X interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
- X if (makedir(buf,MD_DIR)) /* ensure directory exists */
- X strcpy(buf,cwd);
- X if (*s) {
- X for (c = buf; *c; c++) ;
- X *c++ = '/';
- X strcpy(c,s); /* add filename */
- X }
- X s = buf;
- X }
- X for (iter = 0;
- X (there = stat(s,&filestat) >= 0) &&
- X (filestat.st_mode & S_IFDIR);
- X iter++) { /* is it a directory? */
- X
- X c = (s+strlen(s));
- X *c++ = '/'; /* put a slash before filename */
- X interp(c, s==buf?(sizeof buf):(sizeof altbuf),
- X iter ? "News" : savename );
- X /* generate a default name somehow or other */
- X }
- X makedir(s,MD_FILE);
- X if (*s != '/') { /* relative path? */
- X c = (s==buf ? altbuf : buf);
- X sprintf(c, "%s/%s", cwd, s);
- X s = c; /* absolutize it */
- X }
- X if (savedest)
- X free(savedest);
- X s = savedest = savestr(s); /* doesn't move any more */
- X /* make it handy for %b */
- X if (!there) {
- X if (mbox_always)
- X mailbox = TRUE;
- X else if (norm_always)
- X mailbox = FALSE;
- X else {
- X char *dflt = (instr(savename,"%a", TRUE) ? "nyq" : "ynq");
- X
- X sprintf(cmd_buf,
- X "\nFile %s doesn't exist--\n use mailbox format? [%s] ",
- X s,dflt);
- X reask_save:
- X in_char(cmd_buf, 'M');
- X putchar('\n') FLUSH;
- X setdef(buf,dflt);
- X#ifdef VERIFY
- X printcmd();
- X#endif
- X if (*buf == 'h') {
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n\
- Type y to create %s as a mailbox.\n\
- Type n to create it as a normal file.\n\
- Type q to abort the save.\n\
- X",s) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n\
- y to create mailbox.\n\
- n to create normal file.\n\
- q to abort.\n\
- X",stdout) FLUSH;
- X#endif
- X goto reask_save;
- X }
- X else if (*buf == 'n') {
- X mailbox = FALSE;
- X }
- X else if (*buf == 'y') {
- X mailbox = TRUE;
- X }
- X else if (*buf == 'q') {
- X goto s_bomb;
- X }
- X else {
- X fputs(hforhelp,stdout) FLUSH;
- X settle_down();
- X goto reask_save;
- X }
- X }
- X }
- X else if (filestat.st_mode & S_IFCHR)
- X mailbox = FALSE;
- X else {
- X int tmpfd;
- X
- X tmpfd = open(s,0);
- X if (tmpfd == -1)
- X mailbox = FALSE;
- X else {
- X if (read(tmpfd,buf,LBUFLEN)) {
- X c = buf;
- X if (!isspace(MBOXCHAR)) /* if non-zero, */
- X while (isspace(*c)) /* check the first character */
- X c++;
- X mailbox = (*c == MBOXCHAR);
- X } else {
- X mailbox = mbox_always; /* if zero length, recheck -M */
- X }
- X close(tmpfd);
- X }
- X }
- X
- X safecpy(cmd_buf, filexp(mailbox ?
- X getval("MBOXSAVER",MBOXSAVER) :
- X getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
- X /* format the command */
- X termlib_reset();
- X resetty(); /* make terminal behave */
- X if (doshell(use_pref?Nullch:SH,cmd_buf)) {
- X termlib_init();
- X fputs("Not saved",stdout);
- X } else {
- X termlib_init();
- X printf("%s to %s %s",
- X there?"Appended":"Saved",
- X mailbox?"mailbox":"file",
- X s);
- X }
- X if (interactive)
- X putchar('\n') FLUSH;
- X noecho(); /* make terminal do what we want */
- X crmode();
- X }
- s_bomb:
- X#ifdef SERVER
- X if (chdir(spool)) {
- X#else /* not SERVER */
- X if (chdir(spool) || chdir(ngdir)) {
- X#endif /* SERVER */
- X printf(nocd,ngdir) FLUSH;
- X sig_catcher(0);
- X }
- X return SAVE_DONE;
- X}
- X
- int
- cancel_article()
- X{
- X char *artid_buf;
- X char *ngs_buf;
- X char *from_buf;
- X char *reply_buf;
- X int myuid = getuid();
- X int r = -1;
- X
- X if (artopen(art) == Nullfp) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\
- Cancelling null articles is your idea of fun? :-)\n\
- X",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs(nullart,stdout) FLUSH;
- X#endif
- X return r;
- X }
- X reply_buf = fetchlines(art,REPLY_LINE);
- X from_buf = fetchlines(art,FROM_LINE);
- X artid_buf = fetchlines(art,ARTID_LINE);
- X ngs_buf = fetchlines(art,NGS_LINE);
- X if (!instr(from_buf,sitename,FALSE) ||
- X (!instr(from_buf,logname,TRUE) &&
- X !instr(reply_buf,logname,TRUE) &&
- X#ifdef NEWSADMIN
- X myuid != newsuid &&
- X#endif
- X myuid != ROOTID ) ) {
- X#ifdef DEBUGGING
- X if (debug)
- X printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
- X#endif
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\nYou can't cancel someone else's article\n",stdout)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNot your article\n",stdout) FLUSH;
- X#endif
- X }
- X else {
- X tmpfp = fopen(headname,"w"); /* open header file */
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X goto no_cancel;
- X }
- X interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
- X fputs(buf,tmpfp);
- X fclose(tmpfp);
- X fputs("\nCanceling...\n",stdout) FLUSH;
- X r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
- X }
- no_cancel:
- X free(artid_buf);
- X free(ngs_buf);
- X free(from_buf);
- X free(reply_buf);
- X return r;
- X}
- X
- int
- supersede_article() /* Supersedes: */
- X{
- X char *artid_buf;
- X char *ngs_buf;
- X char *from_buf;
- X char *reply_buf;
- X int myuid = getuid();
- X int r = -1;
- X
- X if (artopen(art) == Nullfp) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\
- Superceding null articles is your idea of fun? :-)\n\
- X",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs(nullart,stdout) FLUSH;
- X#endif
- X return r;
- X }
- X reply_buf = fetchlines(art,REPLY_LINE);
- X from_buf = fetchlines(art,FROM_LINE);
- X artid_buf = fetchlines(art,ARTID_LINE);
- X ngs_buf = fetchlines(art,NGS_LINE);
- X if (!instr(from_buf,sitename,FALSE) ||
- X (!instr(from_buf,logname,TRUE) &&
- X !instr(reply_buf,logname,TRUE) &&
- X#ifdef NEWSADMIN
- X myuid != newsuid &&
- X#endif
- X myuid != ROOTID ) ) {
- X#ifdef DEBUGGING
- X if (debug)
- X printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
- X#endif
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\nYou can't supersede someone else's article\n",stdout)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNot your article\n",stdout) FLUSH;
- X#endif
- X }
- X else {
- X tmpfp = fopen(headname,"w"); /* open header file */
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X goto no_commute;
- X }
- X interp(buf, (sizeof buf), getval("SUPERSEDEHEADER",SUPERSEDEHEADER));
- X fputs(buf,tmpfp);
- X fclose(tmpfp);
- X safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),
- X sizeof cmd_buf);
- X invoke(cmd_buf,origdir);
- X r = 0;
- X }
- no_commute:
- X free(artid_buf);
- X free(ngs_buf);
- X free(from_buf);
- X free(reply_buf);
- X return r;
- X}
- X
- void
- reply()
- X{
- X bool incl_body = (*buf == 'R');
- X char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));
- X
- X artopen(art);
- X tmpfp = fopen(headname,"w"); /* open header file */
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X goto no_reply;
- X }
- X interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
- X fputs(buf,tmpfp);
- X if (!instr(maildoer,"%h",TRUE))
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
- X#endif
- X if (incl_body && artfp != Nullfp) {
- X interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
- X fprintf(tmpfp,"%s\n",buf);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- X while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- X fprintf(tmpfp,"%s%s",indstr,buf);
- X }
- X fprintf(tmpfp,"\n");
- X }
- X fclose(tmpfp);
- X interp(cmd_buf, (sizeof cmd_buf), maildoer);
- X invoke(cmd_buf,origdir);
- X UNLINK(headname); /* kill the header file */
- no_reply:
- X free(maildoer);
- X}
- X
- void
- followup()
- X{
- X bool incl_body = (*buf == 'F');
- X char hbuf[4*LBUFLEN]; /* four times the old size */
- X ART_NUM oldart = art;
- X
- X if (!incl_body && art <= lastart) {
- X in_char("\n\nAre you starting an unrelated topic? [yn] ", 'F');
- X setdef(buf,"y");
- X if (*buf != 'n')
- X art = lastart + 1;
- X }
- X artopen(art);
- X tmpfp = fopen(headname,"w");
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X art = oldart;
- X return;
- X }
- X interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
- X fprintf(tmpfp,"%s",hbuf);
- X if (incl_body && artfp != Nullfp) {
- X#ifdef VERBOSE
- X if (verbose)
- X fputs("\n\
- X(Be sure to double-check the attribution against the signature, and\n\
- trim the quoted article down as much as possible.)\n\
- X",stdout) FLUSH;
- X#endif
- X interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
- X fprintf(tmpfp,"%s\n",buf);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- X while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- X fprintf(tmpfp,"%s%s",indstr,buf);
- X }
- X fprintf(tmpfp,"\n");
- X }
- X fclose(tmpfp);
- X safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
- X invoke(cmd_buf,origdir);
- X UNLINK(headname);
- X art = oldart;
- X}
- X
- void
- invoke(cmd,dir)
- char *cmd,*dir;
- X{
- X if (chdir(dir)) {
- X printf(nocd,dir) FLUSH;
- X return;
- X }
- X termlib_reset();
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
- X dir,cmd) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
- X#endif
- X resetty(); /* make terminal well-behaved */
- X doshell(sh,cmd); /* do the command */
- X noecho(); /* set no echo */
- X crmode(); /* and cbreak mode */
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n(+cbreak)\n",stdout) FLUSH;
- X#endif
- X termlib_init();
- X#ifdef SERVER
- X if (chdir(spool)) {
- X#else /* not SERVER */
- X if (chdir(spool) || chdir(ngdir)) {
- X#endif /* SERVER */
- X printf(nocd,ngdir) FLUSH;
- X sig_catcher(0);
- X }
- X}
- X
- X/*
- X** cut_line() determines if a line is meant as a "cut here" marker.
- X** Some examples that we understand:
- X**
- X** BEGIN--cut here--cut here
- X**
- X** ------------------ tear at this line ------------------
- X**
- X** #----cut here-----cut here-----cut here-----cut here----#
- X*/
- bool
- cut_line(str)
- char *str;
- X{
- X char *cp, got_flag;
- X char word[80];
- X int dash_cnt, equal_cnt, other_cnt;
- X
- X /* Disallow any single-/double-quoted, parenthetical or c-commented
- X ** string lines. Make sure it has the cut-phrase and at least six
- X ** '-'s or '='s. If only four '-'s are present, check for a duplicate
- X ** of the cut phrase. If over 20 unknown characters are encountered,
- X ** assume it isn't a cut line. If we succeed, return TRUE.
- X */
- X for (cp = str, dash_cnt = equal_cnt = other_cnt = 0; *cp; cp++) {
- X switch (*cp) {
- X case '-':
- X dash_cnt++;
- X break;
- X case '=':
- X equal_cnt++;
- X break;
- X case '/':
- X if(*(cp+1) != '*') {
- X break;
- X }
- X case '"':
- X case '\'':
- X case '(':
- X case ')':
- X case '[':
- X case ']':
- X case '{':
- X case '}':
- X return FALSE;
- X default:
- X other_cnt++;
- X break;
- X }
- X }
- X if (dash_cnt < 4 && equal_cnt < 6)
- X return FALSE;
- X
- X got_flag = 0;
- X
- X for (*(cp = word) = '\0'; *str; str++) {
- X if (islower(*str))
- X *cp++ = *str;
- X else if (isupper(*str))
- X *cp++ = tolower(*str);
- X else {
- X if (*word) {
- X *cp = '\0';
- X switch (got_flag) {
- X case 2:
- X if (!strcmp(word, "line")
- X || !strcmp(word, "here"))
- X if ((other_cnt -= 4) <= 20)
- X return TRUE;
- X break;
- X case 1:
- X if (!strcmp(word, "this")) {
- X got_flag = 2;
- X other_cnt -= 4;
- X }
- X else if (!strcmp(word, "here")) {
- X other_cnt -= 4;
- X if ((dash_cnt >= 6 || equal_cnt >= 6)
- X && other_cnt <= 20)
- X return TRUE;
- X dash_cnt = 6;
- X got_flag = 0;
- X }
- X break;
- X case 0:
- X if (!strcmp(word, "cut")
- X || !strcmp(word, "snip")
- X || !strcmp(word, "tear")) {
- X got_flag = 1;
- X other_cnt -= strlen(word);
- X }
- X break;
- X }
- X *(cp = word) = '\0';
- X }
- X }
- X } /* for *str */
- X
- X return FALSE;
- X}
- END_OF_FILE
- if test 19717 -ne `wc -c <'respond.c'`; then
- echo shar: \"'respond.c'\" unpacked with wrong size!
- fi
- # end of 'respond.c'
- fi
- if test -f 'rt-rn.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rt-rn.c'\"
- else
- echo shar: Extracting \"'rt-rn.c'\" \(21936 characters\)
- sed "s/^X//" >'rt-rn.c' <<'END_OF_FILE'
- X/* $Id: rt-rn.c,v 4.4.3.1 1991/11/22 04:12:18 davison Trn $
- X**
- X** $Log: rt-rn.c,v $
- X** Revision 4.4.3.1 1991/11/22 04:12:18 davison
- X** Trn Release 2.0
- X**
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "term.h"
- X#include "final.h"
- X#include "util.h"
- X#include "bits.h"
- X#include "artio.h"
- X#include "ng.h"
- X#include "ngdata.h"
- X#include "search.h"
- X#include "artstate.h"
- X#include "backpage.h"
- X
- X#ifdef USETHREADS
- X
- X#include "threads.h"
- X#include "rthreads.h"
- X
- static void find_depth(), cache_tree(), display_tree();
- static char letter();
- X
- X/* Find the article structure information based on article number.
- X*/
- void
- find_article(artnum)
- ART_NUM artnum;
- X{
- X register PACKED_ARTICLE *article;
- X register int i;
- X
- X if (!p_articles) {
- X p_art = Nullart;
- X return;
- X }
- X
- X if (!p_art) {
- X p_art = p_articles;
- X }
- X /* Start looking for the article num from our last known spot in the array.
- X ** That way, if we already know where we are, we run into ourselves right
- X ** away.
- X */
- X for (article=p_art, i=p_art-p_articles; i < total.article; article++,i++) {
- X if (article->num == artnum) {
- X p_art = article;
- X return;
- X }
- X }
- X /* Didn't find it, so search the ones before our current position.
- X */
- X for (article = p_articles; article != p_art; article++) {
- X if (article->num == artnum) {
- X p_art = article;
- X return;
- X }
- X }
- X p_art = Nullart;
- X}
- X
- static char tree_indent[] = {
- X ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0
- X};
- X
- char letters[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?";
- X
- static PACKED_ARTICLE *tree_article;
- X
- static int max_depth, max_line = -1;
- static int first_depth, first_line;
- static int my_depth, my_line;
- static bool node_on_line;
- static int node_line_cnt;
- X
- static int line_num;
- static int header_indent;
- X
- static char *tree_lines[11];
- static char tree_buff[128], *str;
- X
- X/* Prepare tree display for inclusion in the article header.
- X*/
- void
- init_tree()
- X{
- X register PACKED_ARTICLE *article;
- X
- X while (max_line >= 0) { /* free any previous tree data */
- X free(tree_lines[max_line--]);
- X }
- X tree_article = curr_p_art;
- X
- X if (!curr_p_art) {
- X return;
- X }
- X article = p_articles + p_roots[curr_p_art->root].articles;
- X
- X max_depth = max_line = my_depth = my_line = node_line_cnt = 0;
- X find_depth(article, 0);
- X
- X if (max_depth <= 5) {
- X first_depth = 0;
- X } else {
- X if (my_depth+2 > max_depth) {
- X first_depth = max_depth - 5;
- X } else if ((first_depth = my_depth - 3) < 0) {
- X first_depth = 0;
- X }
- X max_depth = first_depth + 5;
- X }
- X if (--max_line < max_tree_lines) {
- X first_line = 0;
- X } else {
- X if (my_line + max_tree_lines/2 > max_line) {
- X first_line = max_line - (max_tree_lines-1);
- X } else if ((first_line = my_line - (max_tree_lines-1)/2) < 0) {
- X first_line = 0;
- X }
- X max_line = first_line + max_tree_lines-1;
- X }
- X
- X str = tree_buff; /* initialize first line's data */
- X *str++ = ' ';
- X node_on_line = FALSE;
- X line_num = 0;
- X /* cache our portion of the tree */
- X cache_tree(article, 0, tree_indent);
- X
- X max_depth = (max_depth-first_depth) * 5; /* turn depth into char width */
- X max_line -= first_line; /* turn max_line into count */
- X /* shorten tree if lower lines aren't visible */
- X if (node_line_cnt < max_line) {
- X max_line = node_line_cnt + 1;
- X }
- X}
- X
- X/* A recursive routine to find the maximum tree extents and where we are.
- X*/
- static void
- find_depth(article, depth)
- PACKED_ARTICLE *article;
- int depth;
- X{
- X if (depth > max_depth) {
- X max_depth = depth;
- X }
- X for (;;) {
- X if (article == tree_article) {
- X my_depth = depth;
- X my_line = max_line;
- X }
- X if (article->child_cnt) {
- X find_depth(article+1, depth+1);
- X } else {
- X max_line++;
- X }
- X if (!article->siblings) {
- X break;
- X }
- X article += article->siblings;
- X }
- X}
- X
- X/* Place the tree display in a maximum of 11 lines x 6 nodes.
- X*/
- static void
- cache_tree(article, depth, cp)
- PACKED_ARTICLE *article;
- int depth;
- char *cp;
- X{
- X int depth_mode;
- X
- X cp[1] = ' ';
- X if (depth >= first_depth && depth <= max_depth) {
- X cp += 5;
- X depth_mode = 1;
- X } else if (depth+1 == first_depth) {
- X depth_mode = 2;
- X } else {
- X cp = tree_indent;
- X depth_mode = 0;
- X }
- X for (;;) {
- X switch (depth_mode) {
- X case 1: {
- X char ch;
- X
- X *str++ = (article->flags & ROOT_ARTICLE)? ' ' : '-';
- X if (article == tree_article) {
- X *str++ = '*';
- X }
- X if (was_read(article->num)) {
- X *str++ = '(';
- X ch = ')';
- X } else {
- X *str++ = '[';
- X ch = ']';
- X }
- X if (article == recent_p_art && article != tree_article) {
- X *str++ = '@';
- X }
- X *str++ = letter(article);
- X *str++ = ch;
- X if (article->child_cnt) {
- X *str++ = (article->child_cnt == 1)? '-' : '+';
- X }
- X if (article->siblings) {
- X *cp = '|';
- X } else {
- X *cp = ' ';
- X }
- X node_on_line = TRUE;
- X break;
- X }
- X case 2:
- X *tree_buff = (!article->child_cnt)? ' ' :
- X (article->child_cnt == 1)? '-' : '+';
- X break;
- X default:
- X break;
- X }
- X if (article->child_cnt) {
- X cache_tree(article+1, depth+1, cp);
- X cp[1] = '\0';
- X } else {
- X if (!node_on_line && first_line == line_num) {
- X first_line++;
- X }
- X if (line_num >= first_line) {
- X if (str[-1] == ' ') {
- X str--;
- X }
- X *str = '\0';
- X tree_lines[line_num-first_line]
- X = safemalloc(str-tree_buff + 1);
- X strcpy(tree_lines[line_num - first_line], tree_buff);
- X if (node_on_line) {
- X node_line_cnt = line_num - first_line;
- X }
- X }
- X line_num++;
- X node_on_line = FALSE;
- X }
- X if (!article->siblings || line_num > max_line) {
- X break;
- X }
- X article += article->siblings;
- X if (!article->siblings) {
- X *cp = '\\';
- X }
- X if (!first_depth) {
- X tree_indent[5] = ' ';
- X }
- X strcpy(tree_buff, tree_indent+5);
- X str = tree_buff + strlen(tree_buff);
- X }
- X}
- X
- X/* Output a header line with possible tree display on the right hand side.
- X** Does automatic wrapping of lines that are too long.
- X*/
- int
- tree_puts(orig_line, header_line, use_underline)
- char *orig_line;
- ART_LINE header_line;
- int use_underline;
- X{
- X char *buf;
- X register char *line, *cp, *end;
- X int pad_cnt, wrap_at;
- X ART_LINE start_line = header_line;
- X int i;
- X char ch;
- X
- X /* Make a modifiable copy of the line */
- X buf = safemalloc(strlen(orig_line) + 2); /* yes, I mean "2" */
- X strcpy(buf, orig_line);
- X line = buf;
- X
- X /* Change any embedded control characters to spaces */
- X for (end = line; *end && *end != '\n'; end++) {
- X if ((unsigned char)*end < ' ') {
- X *end = ' ';
- X }
- X }
- X *end = '\0';
- X
- X if (!*line) {
- X strcpy(line, " ");
- X end = line+1;
- X }
- X
- X /* If this is the first subject line, output it with a preceeding [1] */
- X if (use_underline && curr_p_art && (unsigned char)*line > ' ') {
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X putchar('[');
- X putchar(letter(curr_p_art));
- X putchar(']');
- X un_standout();
- X putchar(' ');
- X header_indent = 4;
- X line += 9;
- X i = 0;
- X } else {
- X if (*line != ' ') {
- X /* A "normal" header line -- output keyword and set header_indent
- X ** _except_ for the first line, which is a non-standard header.
- X */
- X if (!header_line || !(cp = index(line, ':')) || *++cp != ' ') {
- X header_indent = 0;
- X } else {
- X *cp = '\0';
- X fputs(line, stdout);
- X putchar(' ');
- X header_indent = ++cp - line;
- X line = cp;
- X }
- X i = 0;
- X } else {
- X /* Skip whitespace of continuation lines and prepare to indent */
- X while (*++line == ' ') {
- X ;
- X }
- X i = header_indent;
- X }
- X }
- X for (; *line; i = header_indent) {
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X if (i) {
- X putchar('+');
- X while (--i) {
- X putchar(' ');
- X }
- X }
- X /* If no (more) tree lines, wrap at COLS-1 */
- X if (max_line < 0 || header_line > max_line+1) {
- X wrap_at = COLS-1;
- X } else {
- X wrap_at = COLS - max_depth - 5 - 3;
- X }
- X /* Figure padding between header and tree output, wrapping long lines */
- X pad_cnt = wrap_at - (end - line + header_indent);
- X if (pad_cnt <= 0) {
- X cp = line + wrap_at - header_indent - 1;
- X pad_cnt = 1;
- X while (cp > line && *cp != ' ') {
- X if (*--cp == ',' || *cp == '.' || *cp == '-' || *cp == '!') {
- X cp++;
- X break;
- X }
- X pad_cnt++;
- X }
- X if (cp == line) {
- X cp += wrap_at - header_indent;
- X pad_cnt = 0;
- X }
- X ch = *cp;
- X *cp = '\0';
- X /* keep rn's backpager happy */
- X vwtary(artline, vrdary(artline - 1));
- X artline++;
- X } else {
- X cp = end;
- X ch = '\0';
- X }
- X if (use_underline) {
- X underprint(line);
- X } else {
- X fputs(line, stdout);
- X }
- X *cp = ch;
- X /* Skip whitespace in wrapped line */
- X while (*cp == ' ') {
- X cp++;
- X }
- X line = cp;
- X /* Check if we've got any tree lines to output */
- X if (wrap_at != COLS-1 && header_line <= max_line) {
- X char *cp1, *cp2;
- X
- X do {
- X putchar(' ');
- X } while (pad_cnt--);
- X /* Check string for the '*' flagging our current node
- X ** and the '@' flagging our prior node.
- X */
- X cp = tree_lines[header_line];
- X cp1 = index(cp, '*');
- X cp2 = index(cp, '@');
- X if (cp1 != Nullch) {
- X *cp1 = '\0';
- X }
- X if (cp2 != Nullch) {
- X *cp2 = '\0';
- X }
- X fputs(cp, stdout);
- X /* Handle standout output for '*' and '@' marked nodes, then
- X ** continue with the rest of the line.
- X */
- X while (cp1 || cp2) {
- X standout();
- X if (cp1 && (!cp2 || cp1 < cp2)) {
- X cp = cp1;
- X cp1 = Nullch;
- X *cp++ = '*';
- X putchar(*cp++);
- X putchar(*cp++);
- X } else {
- X cp = cp2;
- X cp2 = Nullch;
- X *cp++ = '@';
- X }
- X putchar(*cp++);
- X un_standout();
- X if (*cp) {
- X fputs(cp, stdout);
- X }
- X }/* while */
- X }/* if */
- X putchar('\n') FLUSH;
- X header_line++;
- X }/* for remainder of line */
- X
- X /* free allocated copy of line */
- X free(buf);
- X
- X /* return number of lines displayed */
- X return header_line - start_line;
- X}
- X
- X/* Output any parts of the tree that are left to display. Called at the
- X** end of each header.
- X*/
- int
- finish_tree(last_line)
- ART_LINE last_line;
- X{
- X ART_LINE start_line = last_line;
- X
- X while (last_line <= max_line) {
- X artline++;
- X last_line += tree_puts("+", last_line, 0);
- X vwtary(artline, artpos); /* keep rn's backpager happy */
- X }
- X return last_line - start_line;
- X}
- X
- X/* Output the entire article tree for the user.
- X*/
- void
- entire_tree()
- X{
- X int j, root;
- X
- X if (!ThreadedGroup) {
- X ThreadedGroup = use_data(TRUE);
- X find_article(art);
- X curr_p_art = p_art;
- X }
- X if (check_page_line()) {
- X return;
- X }
- X if (!p_art) {
- X#ifdef VERBOSE
- X IF (verbose)
- X fputs("\nNo article tree to display.\n", stdout);
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNo tree.\n", stdout);
- X#endif
- X } else {
- X root = p_art->root;
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X printf("T%ld:\n", (long)p_roots[root].root_num);
- X un_standout();
- X if (check_page_line()) {
- X return;
- X }
- X putchar('\n');
- X for (j = 0; j < p_roots[root].subject_cnt; j++) {
- X sprintf(buf, "[%c] %s\n", letters[j > 9+26+26 ? 9+26+26 : j],
- X subject_ptrs[root_subjects[root]+j]);
- X if (check_page_line()) {
- X return;
- X }
- X fputs(buf, stdout);
- X }
- X if (check_page_line()) {
- X return;
- X }
- X putchar('\n');
- X if (check_page_line()) {
- X return;
- X }
- X putchar(' ');
- X buf[3] = '\0';
- X display_tree(p_articles+p_roots[p_art->root].articles, tree_indent);
- X
- X if (check_page_line()) {
- X return;
- X }
- X putchar('\n');
- X }
- X}
- X
- X/* A recursive routine to output the entire article tree.
- X*/
- static void
- display_tree(article, cp)
- PACKED_ARTICLE *article;
- char *cp;
- X{
- X if (cp - tree_indent > COLS || page_line < 0) {
- X return;
- X }
- X cp[1] = ' ';
- X cp += 5;
- X for (;;) {
- X putchar((article->flags & ROOT_ARTICLE)? ' ' : '-');
- X if (was_read(article->num)) {
- X buf[0] = '(';
- X buf[2] = ')';
- X } else {
- X buf[0] = '[';
- X buf[2] = ']';
- X }
- X buf[1] = letter(article);
- X if (article == curr_p_art) {
- X standout();
- X fputs(buf, stdout);
- X un_standout();
- X } else if (article == recent_p_art) {
- X putchar(buf[0]);
- X standout();
- X putchar(buf[1]);
- X un_standout();
- X putchar(buf[2]);
- X } else {
- X fputs(buf, stdout);
- X }
- X
- X if (article->siblings) {
- X *cp = '|';
- X } else {
- X *cp = ' ';
- X }
- X if (article->child_cnt) {
- X putchar((article->child_cnt == 1)? '-' : '+');
- X display_tree(article+1, cp);
- X cp[1] = '\0';
- X } else {
- X putchar('\n') FLUSH;
- X }
- X if (!article->siblings) {
- X break;
- X }
- X article += article->siblings;
- X if (!article->siblings) {
- X *cp = '\\';
- X }
- X tree_indent[5] = ' ';
- X if (check_page_line()) {
- X return;
- X }
- X fputs(tree_indent+5, stdout);
- X }
- X}
- X
- int
- check_page_line()
- X{
- X if (page_line < 0) {
- X return -1;
- X }
- X if (page_line >= LINES || int_count) {
- X register int cmd = -1;
- X if (int_count || (cmd = get_anything())) {
- X page_line = -1; /* disable further printing */
- X if (cmd > 0) {
- X pushchar(cmd);
- X }
- X return cmd;
- X }
- X }
- X page_line++;
- X return 0;
- X}
- X
- X/* Calculate the subject letter representation. "Place-holder" nodes
- X** are marked with a ' ', others get a letter in the sequence:
- X** ' ', '1'-'9', 'A'-'Z', 'a'-'z', '?'
- X*/
- static char
- letter(article)
- PACKED_ARTICLE *article;
- X{
- X register int subj = article->subject;
- X
- X if (subj < 0) {
- X return ' ';
- X }
- X subj -= root_subjects[article->root];
- X if (subj < 9+26+26) {
- X return letters[subj];
- X }
- X return '?';
- X}
- X
- X/* Find the first unread article in the (possibly selected) root order.
- X*/
- void
- first_art()
- X{
- X if (!ThreadedGroup) {
- X art = firstart;
- X return;
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X follow_thread('n');
- X}
- X
- X/* Perform a command over all or a section of the article tree. Most of
- X** the option letters match commands entered from article mode:
- X** n - find the next unread article after current article.
- X** ^N - find the next unread article with the same subject.
- X** N - goto the next article in the thread.
- X** j - junk the entire thread.
- X** J - junk the entire thread, chasing xrefs.
- X** k - junk all articles with this same subject, chasing xrefs.
- X** K - kill all this article's descendants, chasing xrefs (we know that
- X** the caller killed the current article on the way here).
- X** u - mark entire thread as "unread".
- X** U - mark this article and its descendants as "unread".
- X** x - go through the unread articles and just chase their xrefs.
- X** f - follow the thread (like 'n'), but don't attempt to find a new thread
- X** if we run off the end.
- X*/
- void
- follow_thread(cmd)
- char_int cmd;
- X{
- X int curr_subj = -1, selected;
- X PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
- X bool subthread_flag, chase_flag;
- X
- X reread = FALSE;
- X
- X if (cmd == 'N') {
- X reread = TRUE;
- X }
- X if (!p_art) {
- X if (ThreadedGroup && art > lastart) {
- X p_art = root_limit = p_articles;
- X goto follow_root;
- X }
- X art++;
- X return;
- X }
- X if (cmd == 'k' || cmd == Ctl('n')) {
- X if ((curr_subj = p_art->subject) == -1) {
- X return;
- X }
- X p_art_old = p_art;
- X }
- X selected = (selected_roots[p_art->root] & 1);
- X if (cmd == 'U' || cmd == 'K') {
- X subthread_flag = TRUE;
- X p_art_old = p_art;
- X } else {
- X subthread_flag = FALSE;
- X }
- X chase_flag = (!olden_days && (cmd == 'J' || cmd == 'k' || cmd == 'K'));
- X
- X /* Some commands encompass the entire thread */
- X if (cmd == 'k' || cmd == 'j' || cmd == 'J' || cmd == 'u' || cmd == 'x') {
- X p_art = p_articles + p_roots[p_art->root].articles;
- X art = p_art->num;
- X }
- X /* The current article is already marked as read for 'K' */
- X if (cmd == 'k' || cmd == 'j' || cmd == 'J') {
- X if (!was_read(art) && (curr_subj < 0 || curr_subj == p_art->subject)) {
- X set_read(art, selected, chase_flag);
- X }
- X cmd = 'K';
- X }
- X if (cmd == 'u') {
- X p_art_old = p_art;
- X cmd = 'U';
- X }
- X if (cmd == 'U') {
- X if (p_art->subject != -1) {
- X set_unread(art, selected);
- X }
- X root_article_cnts[p_art->root] = 1;
- X scan_all_roots = FALSE;
- X }
- X if (cmd == 'x') {
- X if (olden_days) {
- X return;
- X }
- X if ((p_art->flags & HAS_XREFS) && !was_read(art)) {
- X chase_xrefs(art, TRUE);
- X }
- X }
- X follow_again:
- X selected = (selected_roots[p_art->root] & 1);
- X root_limit = upper_limit(p_art, subthread_flag);
- X for (;;) {
- X if (++p_art == root_limit) {
- X break;
- X }
- X if (!(art = p_art->num)) {
- X continue;
- X }
- X if (cmd == 'K' || p_art->subject == -1) {
- X if (!was_read(art)
- X && (curr_subj < 0 || curr_subj == p_art->subject)) {
- X set_read(art, selected, chase_flag);
- X }
- X } else if (cmd == 'U') {
- X set_unread(art, selected);
- X } else if (cmd == 'x') {
- X if ((p_art->flags & HAS_XREFS) && !was_read(art)) {
- X chase_xrefs(art, TRUE);
- X }
- X } else if (!was_read(art)
- X && (curr_subj < 0 || curr_subj == p_art->subject)) {
- X return;
- X } else if (cmd == 'N') {
- X return;
- X }
- X }/* for */
- X if (p_art_old) {
- X p_art = p_art_old;
- X if (cmd == 'U' && p_art->subject != -1) {
- X art = p_art->num;
- X return;
- X }
- X p_art_old = Nullart;
- X cmd = 'n';
- X curr_subj = -1;
- X subthread_flag = FALSE;
- X goto follow_again;
- X }
- X if (cmd == 'f') {
- X p_art = Nullart;
- X art = lastart+1;
- X return;
- X }
- X follow_root:
- X if (root_limit != p_articles + total.article) {
- X register int r;
- X
- X for (r = p_art->root; r < total.root; r++) {
- X if (!selected_root_cnt || selected_roots[r]) {
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if (p_art->subject == -1 || (cmd != 'N' && was_read(art))) {
- X if (cmd != 'N') {
- X cmd = 'n';
- X }
- X curr_subj = -1;
- X subthread_flag = FALSE;
- X goto follow_again;
- X }
- X return;
- X }
- X }
- X }
- X if (!count_roots(FALSE) && unthreaded) {
- X /* No threaded articles left -- blow everything else away */
- X for (art = firstbit; art <= lastart; art++) {
- X oneless(art);
- X }
- X unthreaded = 0;
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X if (cmd == 'N') {
- X forcelast = TRUE;
- X reread = FALSE;
- X }
- X}
- X
- X/* Go backward in the article tree. Options match commands in article mode:
- X** p - previous unread article.
- X** ^P - previous unread article with same subject.
- X** P - previous article.
- X*/
- void
- backtrack_thread(cmd)
- char_int cmd;
- X{
- X int curr_subj = -1, selected;
- X PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
- X
- X if (art > lastart) {
- X p_art = p_articles + total.article - 1;
- X root_limit = Nullart;
- X goto backtrack_root;
- X }
- X if (!p_art) {
- X art--;
- X return;
- X }
- X if (cmd == Ctl('p')) {
- X if ((curr_subj = p_art->subject) == -1) {
- X return;
- X }
- X p_art_old = p_art;
- X }
- X backtrack_again:
- X selected = (selected_roots[p_art->root] & 1);
- X root_limit = p_articles + p_roots[p_art->root].articles;
- X for (;;) {
- X if (p_art-- == root_limit) {
- X break;
- X }
- X if (!(art = p_art->num)) {
- X continue;
- X }
- X if (p_art->subject == -1) {
- X set_read(art, selected, FALSE);
- X } else if (!was_read(art)
- X && (curr_subj < 0 || curr_subj == p_art->subject)) {
- X return;
- X } else if (cmd == 'P') {
- X reread = TRUE;
- X return;
- X }
- X }/* for */
- X if (p_art_old) {
- X p_art = p_art_old;
- X p_art_old = Nullart;
- X curr_subj = -1;
- X goto backtrack_again;
- X }
- X backtrack_root:
- X if (root_limit != p_articles) {
- X register int r;
- X
- X for (r = p_art->root; r >= 0; r--) {
- X if (!selected_root_cnt || selected_roots[r]) {
- X art = p_art->num;
- X if (cmd != 'P' && was_read(art)) {
- X goto backtrack_again;
- X }
- X return;
- X }
- X p_art = p_articles + p_roots[r].articles - 1;
- X }
- X }
- X p_art = Nullart;
- X art = absfirst-1;
- X}
- X
- X/* Find the next root (first if p_art == NULL). If roots are selected,
- X** only choose from selected roots.
- X*/
- void
- next_root()
- X{
- X register int r;
- X
- X reread = FALSE;
- X
- X if (p_art) {
- X r = p_art->root+1;
- X } else {
- X r = 0;
- X }
- X for (; r < total.root; r++) {
- X if (!selected_root_cnt || selected_roots[r]) {
- X try_again:
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if (p_art->subject == -1 || (!reread && was_read(art))) {
- X follow_thread(reread ? 'N' : 'f');
- X if (art == lastart+1) {
- X if (scan_all_roots || selected_root_cnt
- X || root_article_cnts[r]) {
- X reread = TRUE;
- X goto try_again;
- X }
- X continue;
- X }
- X }
- X return;
- X }
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X forcelast = TRUE;
- X}
- X
- X/* Find previous root (or last if p_art == NULL). If roots are selected,
- X** only choose from selected roots.
- X*/
- void
- prev_root()
- X{
- X register int r;
- X
- X reread = FALSE;
- X
- X if (p_art) {
- X r = p_art->root - 1;
- X } else {
- X r = total.root - 1;
- X }
- X for (; r >= 0; r--) {
- X if (!selected_root_cnt || selected_roots[r]) {
- X try_again:
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if (p_art->subject == -1 || (!reread && was_read(art))) {
- X follow_thread(reread ? 'N' : 'f');
- X if (art == lastart+1) {
- X if (scan_all_roots || selected_root_cnt
- X || root_article_cnts[r]) {
- X reread = TRUE;
- X goto try_again;
- X }
- X continue;
- X }
- X }
- X return;
- X }
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X forcelast = TRUE;
- X}
- X
- X/* Return a pointer value that we will equal when we've reached the end of
- X** the current (sub-)thread.
- X*/
- PACKED_ARTICLE *
- upper_limit(artp, subthread_flag)
- PACKED_ARTICLE *artp;
- bool_int subthread_flag;
- X{
- X if (subthread_flag) {
- X for (;;) {
- X if (artp->siblings) {
- X return artp + artp->siblings;
- X }
- X if (!artp->parent) {
- X break;
- X }
- X artp += artp->parent;
- X }
- X }
- X return p_articles + (artp->root == total.root-1 ?
- X total.article : p_roots[artp->root+1].articles);
- X}
- X
- X#endif /* USETHREADS */
- END_OF_FILE
- if test 21936 -ne `wc -c <'rt-rn.c'`; then
- echo shar: \"'rt-rn.c'\" unpacked with wrong size!
- fi
- # end of 'rt-rn.c'
- fi
- if test -f 'rt-select.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rt-select.c'\"
- else
- echo shar: Extracting \"'rt-select.c'\" \(23184 characters\)
- sed "s/^X//" >'rt-select.c' <<'END_OF_FILE'
- X/* $Id: rt-select.c,v 4.4.3.1 1991/11/22 04:12:18 davison Trn $
- X**
- X** $Log: rt-select.c,v $
- X** Revision 4.4.3.1 1991/11/22 04:12:18 davison
- X** Trn Release 2.0
- X**
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "rn.h"
- X#include "rcstuff.h"
- X#include "term.h"
- X#include "final.h"
- X#include "util.h"
- X#include "help.h"
- X#include "bits.h"
- X#include "artsrch.h"
- X#include "ng.h"
- X#include "ngdata.h"
- X#include "ngstuff.h"
- X
- X#ifdef USETHREADS
- X
- X#include "threads.h"
- X#include "rthreads.h"
- X
- static int count_subj_lines();
- static void display_subj();
- X
- X/* When display mode is 'l', each author gets a separate line; when 'm', up to
- X** three authors share a line; when 's', no authors are displayed.
- X*/
- static char *display_mode = select_order;
- static ART_NUM article_count;
- static int author_line;
- static char first_two_chars[3] = { ' ', ' ', '\0' }, mask = 1;
- X
- X#define MAX_SEL 64
- X
- X/* Display a menu of roots for the user to choose from. If cmd is '+'
- X** we display all the unread roots and allow the user to mark roots as
- X** selected and perform various commands upon the articles. If cmd is
- X** 'U' we display all the previously read roots and allow the user to
- X** select which ones should be marked as unread.
- X*/
- char
- select_thread(cmd)
- char_int cmd;
- X{
- X register int i, j, cnt;
- X ART_NUM art_hold = art;
- X int line_cnt, screen_line, subj_line_cnt;
- X int cur_root, page_root, last_root = -1;
- X ART_LINE running_total, last_running;
- X int last_line, got_dash;
- X int max_root;
- X int first, last;
- X int root_line[MAX_SEL], root_hold[MAX_SEL];
- X int ch, action;
- X char page_char, end_char;
- X char promptbuf[80];
- X bool etc, clean_screen, empty_ok, displayed_status;
- X char oldmode = mode;
- X#ifndef CONDSUB
- X char tmpbuf[2];
- X#endif
- X char *select_chars, *in_select;
- X int max_cnt;
- X
- X mode = 't';
- X unread_selector = (cmd == 'U');
- X clear_on_stop = TRUE;
- X empty_ok = FALSE;
- X
- X select_threads:
- X /* Setup for selecting articles to read or set unread */
- X scan_all_roots = FALSE;
- X if (unread_selector) {
- X page_char = '>';
- X end_char = 'Z';
- X page_root = 0;
- X last_root = -1;
- X cmd = 0;
- X } else {
- X page_char = page_select;
- X end_char = end_select;
- X page_root = select_page;
- X if (curr_p_art) {
- X last_root = curr_p_art->root;
- X }
- X }
- X mask = unread_selector+1;
- X
- X /* Leave empty roots selected for a short time to give them a chance
- X ** to Esc out of the selector if they got here by mistake.
- X */
- X max_root = count_roots(FALSE);
- X
- X /* If nothing to display, we're done. */
- X if (!article_count && !empty_ok) {
- X all_empty:
- X clear_on_stop = FALSE;
- X mode = oldmode;
- X putchar('\n');
- X if (unread_selector) {
- X#ifdef VERBOSE
- X IF (verbose)
- X fputs("\nNo articles to set unread.\n", stdout);
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNo articles.\n", stdout) FLUSH;
- X#endif
- X unread_selector = 0;
- X mask = 1;
- X } else {
- X#ifdef VERBOSE
- X IF (verbose)
- X fputs("\nNo unread articles to select.", stdout);
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNo articles.", stdout);
- X#endif
- X#ifndef USETMPTHREAD
- X if (tobethreaded) {
- X printf(" (%d article%s not yet threaded)",
- X tobethreaded, tobethreaded == 1 ? nullstr : "s") FLUSH;
- X }
- X#endif
- X putchar('\n'); /* let "them" FLUSH */
- X }
- X (void) count_roots(TRUE);
- X art = art_hold;
- X p_art = curr_p_art;
- X return '\033';
- X }
- X if (unread_selector) {
- X for (j = 0; j < total.root; j++) {
- X selected_roots[j] |= 4;
- X }
- X }
- X if (page_root >= max_root) {
- X ch = '<';
- X } else {
- X ch = '>';
- X }
- X cur_root = 0;
- X running_total = 0;
- X for (i = 0; i < page_root; i++) {
- X running_total += root_article_cnts[i];
- X }
- X do {
- X select_chars = getval("SELECTCHARS", SELECTCHARS);
- X max_cnt = strlen(select_chars);
- X if (max_cnt > MAX_SEL) {
- X max_cnt = MAX_SEL;
- X }
- X if (ch == '<' && i) {
- X screen_line = 2;
- X cnt = 0;
- X /* Scan the roots in reverse to go back a page */
- X do {
- X if (!root_article_cnts[--i]) {
- X continue;
- X }
- X first = root_subjects[i];
- X last = first + p_roots[i].subject_cnt;
- X line_cnt = 0;
- X for (j = first; j < last; j++) {
- X line_cnt += count_subj_lines(i, j);
- X }
- X if (line_cnt > LINES - 5) {
- X line_cnt = LINES - 5;
- X }
- X screen_line += line_cnt;
- X if (screen_line > LINES - 3) {
- X i++;
- X break;
- X }
- X running_total -= root_article_cnts[i];
- X cnt++;
- X } while (i > 0 && cnt < max_cnt);
- X }
- X
- X /* Present a page of subjects to the user */
- X#ifndef CLEAREOL
- X clear();
- X#else
- X if (can_home_clear) {
- X home_cursor();
- X maybe_eol();
- X } else {
- X clear();
- X }
- X#endif
- X carriage_return();
- X page_root = i;
- X last_running = running_total;
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X fputs(ngname, stdout);
- X un_standout();
- X printf(" %ld %sarticle%s%s\n", (long)article_count,
- X unread_selector? "read " : nullstr,
- X article_count == 1 ? nullstr : "s", moderated);
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar('\n') FLUSH;
- X screen_line = 2;
- X for (cnt = 0; i < max_root && cnt < max_cnt; i++) {
- X if (last_root == i) {
- X cur_root = cnt;
- X }
- X /* Check each root for articles to list */
- X if (!root_article_cnts[i]) {
- X continue;
- X }
- X first = root_subjects[i];
- X last = first + p_roots[i].subject_cnt;
- X
- X /* Compute how many lines we need to display the subjects/authors */
- X etc = FALSE;
- X line_cnt = 0;
- X for (j = first; j < last; j++) {
- X subj_line_cnt = count_subj_lines(i, j);
- X line_cnt += subj_line_cnt;
- X /* If this root is too long to fit on the screen all by
- X ** itself, trim it to fit and set the "etc" flag.
- X */
- X if (line_cnt > LINES - 5) {
- X last = j;
- X line_cnt -= subj_line_cnt;
- X if (line_cnt != LINES - 5) {
- X last++;
- X line_cnt = LINES - 5;
- X }
- X if (screen_line == 2) {
- X etc = TRUE;
- X }
- X break;
- X }
- X }
- X /* If it doesn't fit, save it for the next page */
- X if (screen_line + line_cnt > LINES - 3) {
- X break;
- X }
- X /* Output the subjects, with optional authors */
- X root_line[cnt] = screen_line;
- X running_total += root_article_cnts[i];
- X first_two_chars[0] = select_chars[cnt];
- X first_two_chars[1] = (selected_roots[i] & 4) ? '-' :
- X (selected_roots[i] & mask) ? '+' : ' ';
- X author_line = screen_line;
- X for (j = first; j < last; j++) {
- X display_subj(i, j);
- X }
- X screen_line += line_cnt;
- X root_hold[cnt++] = i;
- X if (etc) {
- X fputs(" ...etc.", stdout);
- X i++;
- X break;
- X }
- X }/* for */
- X last_root = -1;
- X if (cur_root && cur_root >= cnt) {
- X cur_root = cnt - 1;
- X }
- X
- X /* Check if there is really anything left to display. */
- X if (!running_total && !empty_ok) {
- X goto all_empty;
- X }
- X empty_ok = FALSE;
- X
- X last_line = screen_line+1;
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar('\n') FLUSH;
- X /* Prompt the user */
- X#ifdef MAILCALL
- X setmail();
- X#endif
- X if (i != max_root) {
- X sprintf(promptbuf, "%s-- Select threads -- %s%ld%% [%c%c] --",
- X mailcall, (!page_root? "Top " : nullstr),
- X (long)(running_total*100 / article_count),
- X page_char, end_char);
- X } else {
- X sprintf(promptbuf, "%s-- Select threads -- %s [%c%c] --",
- X mailcall, (!page_root? "All" : "Bot"), end_char, page_char);
- X }
- X if (cur_root > cnt) {
- X cur_root = 0;
- X }
- X screen_line = root_line[cur_root];
- X#ifdef CLEAREOL
- X if (erase_screen && can_home_clear) {
- X clear_rest();
- X }
- X#endif
- X displayed_status = FALSE;
- X prompt_select:
- X standout();
- X fputs(promptbuf, stdout);
- X un_standout();
- X if (can_home) {
- X carriage_return();
- X goto_line(last_line, screen_line);
- X }
- X got_dash = 0;
- X /* Grab some commands from the user */
- X for (;;) {
- X fflush(stdout);
- X eat_typeahead();
- X#ifdef CONDSUB
- X getcmd(buf);
- X ch = *buf;
- X#else
- X getcmd(tmpbuf); /* If no conditionals, don't allow macros */
- X ch = *tmpbuf;
- X buf[0] = ch;
- X buf[1] = FINISHCMD;
- X#endif
- X if (errno) {
- X ch = Ctl('l');
- X }
- X in_select = index(select_chars, ch);
- X /* Plaster any inherited empty roots on first command if not Esc. */
- X if (cmd && (in_select || (ch != '\033' && ch != '+'))) {
- X max_root = count_roots(TRUE);
- X cmd = 0;
- X }
- X if (displayed_status && can_home) {
- X goto_line(screen_line, last_line+1);
- X erase_eol();
- X screen_line = last_line+1;
- X displayed_status = FALSE;
- X }
- X if (ch == '-') {
- X got_dash = 1;
- X if (!can_home) {
- X putchar('-');
- X fflush(stdout);
- X }
- X continue;
- X }
- X if (ch == ' ') {
- X if (i == max_root) {
- X ch = end_char;
- X } else {
- X ch = page_char;
- X }
- X }
- X if (!in_select && (index("<+>^$!?&:/hDJLNPqQTUXZ\n\r\t\033", ch)
- X || ch == Ctl('l') || ch == Ctl('r') || ch == Ctl('k'))) {
- X break;
- X }
- X if (in_select) {
- X j = in_select - select_chars;
- X if (j >= cnt) {
- X dingaling();
- X j = -1;
- X } else if (got_dash) {
- X ;
- X } else if (selected_roots[root_hold[j]] & mask) {
- X action = (unread_selector ? 'k' : '-');
- X } else {
- X action = '+';
- X }
- X } else if (ch == 'y' || ch == '.') {
- X j = cur_root;
- X if (selected_roots[root_hold[j]] & mask) {
- X action = (unread_selector ? 'k' : '-');
- X } else {
- X action = '+';
- X }
- X } else if (ch == 'k' || ch == 'j' || ch == ',') {
- X j = cur_root;
- X action = 'k';
- X } else if (ch == 'm' || ch == '\\') {
- X j = cur_root;
- X action = 'm';
- X } else if (ch == '@') {
- X cur_root = 0;
- X j = cnt-1;
- X got_dash = 1;
- X action = '@';
- X } else if (ch == '[' || ch == 'p') {
- X if (--cur_root < 0) {
- X cur_root = cnt ? cnt-1 : 0;
- X }
- X j = -1;
- X } else if (ch == ']' || ch == 'n') {
- X if (++cur_root >= cnt) {
- X cur_root = 0;
- X }
- X j = -1;
- X } else {
- X if (can_home) {
- X goto_line(screen_line, last_line+1);
- X screen_line = last_line+1;
- X } else {
- X putchar('\n');
- X }
- X printf("Type ? for help.");
- X settle_down();
- X displayed_status = TRUE;
- X
- X if (can_home) {
- X carriage_return();
- X } else {
- X putchar('\n');
- X }
- X j = -1;
- X }
- X if (j >= 0) {
- X if (!got_dash) {
- X cur_root = j;
- X } else {
- X got_dash = 0;
- X if (j < cur_root) {
- X ch = cur_root-1;
- X cur_root = j;
- X j = ch;
- X }
- X }
- X if (++j == cnt) {
- X j = 0;
- X }
- X do {
- X register int r;
- X register char maskr = mask;
- X r = root_hold[cur_root];
- X if (can_home) {
- X goto_line(screen_line, root_line[cur_root]);
- X screen_line = root_line[cur_root];
- X }
- X putchar(select_chars[cur_root]);
- X if (action == '@') {
- X if (selected_roots[r] & 4) {
- X ch = (unread_selector ? '+' : ' ');
- X } else if (unread_selector) {
- X ch = 'k';
- X } else
- X if (selected_roots[r] & maskr) {
- X ch = '-';
- X } else {
- X ch = '+';
- X }
- X } else {
- X ch = action;
- X }
- X switch (ch) {
- X case '+':
- X if (!(selected_roots[r] & maskr)) {
- X selected_roots[r] |= maskr;
- X selected_root_cnt++;
- X selected_count += root_article_cnts[r];
- X putchar('+');
- X }
- X /* FALL THROUGH */
- X case 'm':
- X if (selected_roots[r] & 4) {
- X selected_roots[r] &= ~4;
- X if (ch == 'm') {
- X putchar(' ');
- X }
- X } else if (ch == 'm') {
- X goto unsel;
- X }
- X break;
- X case 'k':
- X if (!(selected_roots[r] & 4)) {
- X selected_roots[r] |= 4;
- X putchar('-'), fflush(stdout);
- X p_art = p_articles + p_roots[r].articles;
- X art = 0;
- X follow_thread('x');
- X }
- X /* FALL THROUGH */
- X case '-':
- X unsel:
- X if (selected_roots[r] & maskr) {
- X selected_roots[r] &= ~maskr;
- X selected_root_cnt--;
- X selected_count -= root_article_cnts[r];
- X if (ch != 'k') {
- X putchar(' ');
- X }
- X }
- X break;
- X }
- X fflush(stdout);
- X if (++cur_root == cnt) {
- X cur_root = 0;
- X }
- X if (can_home) {
- X carriage_return();
- X }
- X } while (cur_root != j);
- X } else {
- X got_dash = FALSE;
- X }
- X if (can_home) {
- X goto_line(screen_line, root_line[cur_root]);
- X screen_line = root_line[cur_root];
- X }
- X }/* for */
- X if (can_home) {
- X goto_line(screen_line, last_line);
- X }
- X clean_screen = TRUE;
- X do_command:
- X output_chase_phrase = TRUE;
- X if (ch == 'L') {
- X if (!*++display_mode) {
- X display_mode = select_order;
- X }
- X ch = Ctl('l');
- X cur_root = 0;
- X } else if (ch == '$') {
- X ch = '<';
- X page_root = max_root;
- X last_running = article_count;
- X cur_root = 0;
- X } else if (ch == '^' || ch == Ctl('r')) {
- X ch = '>';
- X i = 0;
- X running_total = 0;
- X cur_root = 0;
- X } else if (ch == 'h' || ch == '?') {
- X putchar('\n');
- X if ((ch = help_select()) || (ch = pause_getcmd())) {
- X goto got_cmd;
- X }
- X ch = Ctl('l');
- X } else if (index(":/&!", ch)) {
- X erase_eol(); /* erase the prompt */
- X if (!finish_command(TRUE)) { /* get rest of command */
- X if (clean_screen) {
- X screen_line = root_line[cur_root];
- X goto prompt_select;
- X }
- X goto extend_done;
- X }
- X if (ch == '&' || ch == '!') {
- X one_command = TRUE;
- X perform(buf, FALSE);
- X one_command = FALSE;
- X
- X putchar('\n') FLUSH;
- X clean_screen = FALSE;
- X } else {
- X int selected_save = selected_root_cnt;
- X
- X if (ch == ':') {
- X clean_screen = (use_selected() == 2) && clean_screen;
- X if (!unread_selector) {
- X for (j = 0; j < total.root; j++) {
- X if (selected_roots[j] & 4) {
- X selected_roots[j] = 0;
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread('j');
- X }
- X }
- X }
- X } else {
- X /* Force the search to begin at absfirst or firstart,
- X ** depending upon whether they specified the 'r' option.
- X */
- X art = lastart+1;
- X page_line = 1;
- X switch (art_search(buf, sizeof buf, FALSE)) {
- X case SRCH_ERROR:
- X case SRCH_ABORT:
- X case SRCH_INTR:
- X fputs("\nInterrupted\n", stdout) FLUSH;
- X break;
- X case SRCH_DONE:
- X case SRCH_SUBJDONE:
- X fputs("Done\n", stdout) FLUSH;
- X break;
- X case SRCH_NOTFOUND:
- X fputs("\nNot found.\n", stdout) FLUSH;
- X break;
- X case SRCH_FOUND:
- X break;
- X }
- X clean_screen = FALSE;
- X }
- X /* Recount, in case something has changed. */
- X max_root = count_roots(!unread_selector);
- X
- X running_total = 0;
- X if (article_count) {
- X for (j = 0; j < page_root; j++) {
- X running_total += root_article_cnts[j];
- X }
- X }
- X cur_root = 0;
- X
- X if ((selected_save -= selected_root_cnt) != 0) {
- X putchar('\n');
- X if (selected_save < 0) {
- X fputs("S", stdout);
- X selected_save *= -1;
- X } else {
- X fputs("Des", stdout);
- X }
- X printf("elected %d thread%s.", selected_save,
- X selected_save == 1 ? nullstr : "s");
- X clean_screen = FALSE;
- X }
- X if (!clean_screen) {
- X putchar('\n') FLUSH;
- X }
- X }/* if !& or :/ */
- X
- X if (clean_screen) {
- X carriage_return();
- X up_line();
- X erase_eol();
- X screen_line = root_line[cur_root];
- X goto prompt_select;
- X }
- X extend_done:
- X if ((ch = pause_getcmd())) {
- X got_cmd:
- X if (ch > 0) {
- X /* try to optimize the screen update for some commands. */
- X if (!index(select_chars, ch)
- X && (index("<+>^$!?&:/hDJLNPqQTUXZ\n\r\t\033", ch)
- X || ch == Ctl('k'))) {
- X buf[0] = ch;
- X buf[1] = FINISHCMD;
- X goto do_command;
- X }
- X pushchar(ch | 0200);
- X }
- X }
- X ch = Ctl('l');
- X } else if (ch == Ctl('k')) {
- X edit_kfile();
- X ch = Ctl('l');
- X } else if (!unread_selector && (ch == 'X' || ch == 'D' || ch == 'J')) {
- X if (ch == 'D') {
- X j = page_root;
- X last = i;
- X } else {
- X j = 0;
- X last = max_root;
- X }
- X for (; j < last; j++) {
- X if (((!(selected_roots[j] & 1) ^ (ch == 'J'))
- X && (cnt = root_article_cnts[j])) || (selected_roots[j] & 4)) {
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread((selected_roots[j] & 4) ? 'j' : 'J');
- X }
- X }
- X max_root = count_roots(TRUE);
- X if (article_count
- X && (ch == 'J' || (ch == 'D' && !selected_root_cnt))) {
- X last_running = 0;
- X for (i = 0; i < page_root; i++) {
- X last_running += root_article_cnts[i];
- X }
- X ch = Ctl('l');
- X cur_root = 0;
- X } else {
- X if (!output_chase_phrase)
- X ch = 'o';
- X break;
- X }
- X } else if (ch == 'J') {
- X for (j = 0; j < max_root; j++) {
- X selected_roots[j] = (selected_roots[j] & ~2) | 4;
- X }
- X selected_root_cnt = selected_count = 0;
- X ch = Ctl('l');
- X } else if (ch == 'T') {
- X register int r;
- X
- X erase_eol(); /* erase the prompt */
- X r = root_hold[cur_root];
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if (p_art->subject == -1) {
- X follow_thread('N');
- X }
- X perform("T", FALSE);
- X max_root = count_roots(TRUE);
- X if (article_count) {
- X ch = Ctl('l');
- X }
- X }
- X if (ch == '>') {
- X cur_root = 0;
- X page_root = i;
- X } else if (ch == '<' || (page_root && page_root >= max_root)) {
- X cur_root = 0;
- X running_total = last_running;
- X if (!(i = page_root) || !max_root) {
- X ch = '>';
- X } else {
- X ch = '<';
- X }
- X } else if (ch == Ctl('l')) {
- X i = page_root;
- X running_total = last_running;
- X ch = '>';
- X } else if (ch == '\r' || ch == '\n') {
- X if (!selected_root_cnt) {
- X register r = root_hold[cur_root];
- X selected_roots[r] = mask;
- X selected_root_cnt++;
- X selected_count += root_article_cnts[r];
- X }
- X }
- X } while ((ch == '>' && i < max_root) || ch == '<');
- X if (ch != 'o') {
- X putchar('\n') FLUSH;
- X }
- X
- X if (unread_selector) {
- X /* Turn selections into unread selected roots. Let count_roots()
- X ** fix the counts after we're through.
- X */
- X last_root = -1;
- X for (j = 0; j < total.root; j++) {
- X if (!(selected_roots[j] & 4)) {
- X if (selected_roots[j] & 2) {
- X selected_roots[j] = 1;
- X }
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread('u');
- X } else {
- X selected_roots[j] &= ~4;
- X }
- X }
- X } else {
- X select_page = page_root;
- X for (j = 0; j < total.root; j++) {
- X if (selected_roots[j] & 4) {
- X selected_roots[j] = 0;
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread('j');
- X }
- X }
- X }
- X if (ch == 'U') {
- X unread_selector = !unread_selector;
- X empty_ok = TRUE;
- X goto select_threads;
- X }
- X
- X if (unread_selector) {
- X unread_selector = 0;
- X mask = 1;
- X (void) count_roots(FALSE);
- X }
- X if (ch == 'N' || ch == 'P' || Ctl(ch) == Ctl('q') || ch == '\033') {
- X art = art_hold;
- X p_art = curr_p_art;
- X } else {
- X first_art();
- X }
- X clear_on_stop = FALSE;
- X mode = oldmode;
- X return ch;
- X}
- X
- static int author_cnt, first_author;
- X
- X/* Counts the number of lines needed to output a subject, including optional
- X** authors.
- X*/
- static int
- count_subj_lines(root, subj)
- int root;
- int subj;
- X{
- X PACKED_ARTICLE *artp, *root_limit;
- X int author_subj;
- X
- X author_cnt = 0;
- X author_subj = subj;
- X first_author = -1;
- X
- X if (!subject_cnts[subj]) {
- X return 0;
- X }
- X if (*display_mode == 's') { /* no-author mode takes one line */
- X return ++author_cnt;
- X }
- X bzero(author_cnts, total.author * sizeof (WORD));
- X
- X /* Count authors associated with this subject. Increments author_cnts. */
- X artp = p_articles + p_roots[root].articles;
- X root_limit = upper_limit(artp, FALSE);
- X for (; artp != root_limit; artp++) {
- X if (artp->subject == author_subj
- X && (!was_read(artp->num) ^ unread_selector)) {
- X if (artp->author < 0 || artp->author >= total.author) {
- X printf("\
- XFound invalid author (%d) with valid subject (%d)! [%ld]\n",
- X artp->author, artp->subject, artp->num);
- X artp->author = 0;
- X } else {
- X if (first_author < 0) {
- X first_author = artp->author;
- X }
- X if (!author_cnts[artp->author]++) {
- X author_cnt++;
- X }
- X }
- X }
- X }
- X
- X if (*display_mode == 'm') {
- X return (author_cnt+4)/3;
- X } else {
- X return author_cnt;
- X }
- X}
- X
- static void
- display_subj(root, subj)
- int root;
- int subj;
- X{
- X PACKED_ARTICLE *artp, *root_limit;
- X char *str;
- X
- X count_subj_lines(root, subj);
- X if (!author_cnt) {
- X return;
- X }
- X artp = p_articles + p_roots[root].articles;
- X if (artp->subject != -1 && (artp->flags & ROOT_ARTICLE)
- X && (!was_read(artp->num) ^ unread_selector)) {
- X str = nullstr;
- X } else {
- X str = ">";
- X }
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X if (*display_mode == 's') {
- X printf("%s%3d %s%.71s\n", first_two_chars,
- X subject_cnts[subj], str, subject_ptrs[subj]) FLUSH;
- X } else {
- X printf("%s%-16.16s%3d %s%.55s", first_two_chars,
- X author_ptrs[first_author],
- X subject_cnts[subj], str, subject_ptrs[subj]);
- X if (author_cnt > 1) {
- X author_cnts[first_author] = 0;
- X author_cnt = 0;
- X root_limit = upper_limit(artp, FALSE);
- X for (; artp != root_limit; artp++) {
- X if (artp->author >= 0 && author_cnts[artp->author]) {
- X switch (author_cnt % 3) {
- X case 0:
- X putchar('\n') FLUSH;
- X if (++author_line >= LINES - 3) {
- X return;
- X }
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar(' ');
- X putchar(' ');
- X break;
- X case 1:
- X putchar('\t');
- X putchar('\t');
- X break;
- X case 2:
- X putchar('\t');
- X break;
- X }
- X author_cnt += (*display_mode == 'm');
- X printf("%-16.16s", author_ptrs[artp->author]);
- X author_cnts[artp->author] = 0;
- X }/* if */
- X }/* for */
- X }/* if */
- X putchar('\n') FLUSH;
- X author_line++;
- X }/* if */
- X first_two_chars[0] = first_two_chars[1] = ' ';
- X}
- X
- X/* Get each root's article count, and subject count(s); count total
- X** articles and selected articles (use unread_selector to determine
- X** whether to count read or unread articles); deselect any roots we
- X** find that are empty (if do_unselect is TRUE); find the last non-
- X** empty root, and return its count (the index+1).
- X*/
- int
- count_roots(do_unselect)
- bool_int do_unselect;
- X{
- X register int count;
- X register PACKED_ARTICLE *artp, *root_limit, *art_limit;
- X int last_root = -1;
- X
- X article_count = selected_count = selected_root_cnt = 0;
- X
- X if (!(artp = p_articles)) {
- X return 0;
- X }
- X art_limit = artp + total.article;
- X root_limit = upper_limit(artp, 0);
- X
- X bzero(subject_cnts, total.subject * sizeof (WORD));
- X count = 0;
- X
- X for (;;) {
- X if (artp->subject == -1) {
- X if (!was_read(artp->num)) {
- X oneless(artp->num);
- X }
- X } else if ((!was_read(artp->num) ^ unread_selector)) {
- X count++;
- X subject_cnts[artp->subject]++;
- X }
- X if (++artp == root_limit) {
- X register int root_num = artp[-1].root;
- X register char maskr = mask;
- X
- X root_article_cnts[root_num] = count;
- X if (count) {
- X article_count += count;
- X if (selected_roots[root_num] & maskr) {
- X selected_roots[root_num] &= ~4;
- X selected_root_cnt++;
- X selected_count += count;
- X }
- X last_root = root_num;
- X } else if (do_unselect) {
- X selected_roots[root_num] &= ~maskr;
- X } else if (selected_roots[root_num] & maskr) {
- X selected_roots[root_num] &= ~4;
- X selected_root_cnt++;
- X }
- X if (artp == art_limit) {
- X break;
- X }
- X root_limit = upper_limit(artp, 0);
- X count = 0;
- X }
- X }
- X if (do_unselect) {
- X scan_all_roots = !article_count;
- X }
- X unthreaded = toread[ng] - article_count;
- X
- X return last_root+1;
- X}
- X
- X/* Count the unread articles attached to the given root number.
- X*/
- int
- count_one_root(root_num)
- int root_num;
- X{
- X int last = (root_num == total.root-1 ? total.article
- X : p_roots[root_num+1].articles);
- X register int count = 0, i;
- X
- X for (i = p_roots[root_num].articles; i < last; i++) {
- X if (p_articles[i].subject != -1 && !was_read(p_articles[i].num)) {
- X count++;
- X }
- X }
- X root_article_cnts[root_num] = count;
- X
- X return count;
- X}
- X
- X#endif /* USETHREADS */
- END_OF_FILE
- if test 23184 -ne `wc -c <'rt-select.c'`; then
- echo shar: \"'rt-select.c'\" unpacked with wrong size!
- fi
- # end of 'rt-select.c'
- fi
- echo shar: End of archive 7 \(of 13\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 13 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-